package 三数之和;

import java.util.*;
import java.util.stream.Collectors;

public class Solution {

    /*
    给你一个整数数组 nums ，判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ，同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
    注意：答案中不可以包含重复的三元组。
     */
    public List<List<Integer>> threeSum(int[] nums) {

        // 使用双指针

        List<List<Integer>> result = new ArrayList<>();

        // 将数组进行排序（从小到大）
        Arrays.sort(nums);

        // 固定一个数字，然后在该数字的右边区间查找另外两个数字
        for (int i = 0; i < nums.length; i++) {
            // sum = nums[i] + nums[left] + nums[right]

            // 排序之后如果第一个元素已经大于零，那么无论如何组合都不可能凑成三元组，直接返回结果就可以了
            if (nums[i] > 0) {
                return result;
            }

            // 对 nums[i] 进行去重，为什么不适用 nums[i] == nums[i+1]呢。因为我们的逻辑是nums[i]这个数字的所有结果集合已经在上一次（nums[i-1]）中查找完了
            if (i > 0 && nums[i] == nums[i - 1])
                continue;

            // 查找剩下两个数字
            int left = i + 1;
            int right = nums.length - 1;

            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if ( sum == 0) {
                    // 符合条件，添加到结果集中
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    // 对数字 nums[left] 和 nums[right] 进行去重，为什么逻辑没有放在while中，是因为我们至少需要收集一个结果集（if）我们才需要进行去重
                    while (left < right && nums[right] == nums[right - 1]) right--; // 说明下一个数字也不需要进行验证
                    while (left < right && nums[left] == nums[left + 1]) left++;// 说明下一个数字也不需要进行验证
                    left++;
                    right--;
                }else if ( sum > 0)
                    right--;
                else
                    left++;
            }
        }
        // 返回结果List
        return result;
    }

}
